+2005-08-16 Øyvind Kolås <pippin@gimp.org>
+
+ * babl/babl-fish.c: reindentation, no naming of fishes.
+ * babl/babl-ids.h: reordering, added YCBCRA, LAB and LAB_ALPHA
+ * babl/base/Makefile.am: added cpercep.[ch] model-lab.c and
+ model-ycbcr.c
+ * babl/base/cpercep.[ch]: *NEW*
+ * babl/base/model-lab.c: *NEW* CIE Lab color model, backed by a slightly
+ modified version of cpercep from gimp sources (no gamma correction and
+ normalized RGB values)
+ * babl/base/model-ycbcr: made ycbcr work, numbers still need to be
+ verified.
+ * babl/base/babl-base.c: initialize CIE Lab and YCbCr
+ * babl/base/model-cmyk.c: slight changes, it still doesn't pass
+ rgb->cmyk->rgb testing so not included yet.
+ * babl/base/model-rgb.c: make rgba-double use BABL_DOUBLE instead of
+ BABL_FLOAT
+ * babl/base/type-u16: fix conversion to double.
+ * tests/Makefile.am: added rgb_to_lab_to_rgb , rgb_to_ycbcr_to_rgb and
+ rgb_to_ycbcr
+ * tests/rgb_to_lab_to_rgb.c
+ * tests/rgb_to_ycbcr_to_rgb.c
+ * tests/rgb_to_ycbcr.c: *NEW* tests
+
2005-08-15 Øyvind Kolås <pippin@gimp.org>
* babl/base/model-cmyk.c
Babl *destination)
{
SearchData data;
- data.source = source;
+ data.source = source;
data.destination = destination;
- data.result = NULL;
+ data.result = NULL;
babl_conversion_each (find_conversion, &data);
if (!data.result)
{
- babl_log ("%s('%s', '%s'): failed", __FUNCTION__,
+ babl_log ("%s('%s', '%s'): failed, aborting", __FUNCTION__,
source->instance.name, destination->instance.name);
+ exit (-1);
return NULL;
}
return data.result;
babl = babl_calloc (sizeof (BablFishReference), 1);
babl->class_type = BABL_FISH_REFERENCE;
babl->instance.id = 0;
- babl->instance.name = "Fishy";
+ babl->instance.name = NULL;
babl->fish.source = (union Babl*)source;
babl->fish.destination = (union Babl*)destination;
fooA = babl_malloc(sizeof (double) * n * 4);
fooB = babl_malloc(sizeof (double) * n * 4);
+ assert (babl_fish);
assert (source);
assert (destination);
BABL_RGBA,
BABL_RGBA_GAMMA_2_2,
BABL_RGBA_PREMULTIPLIED,
- BABL_CMY,
- BABL_CMYK,
- BABL_CMYKA,
- BABL_YCBCR,
BABL_GRAYSCALE,
BABL_GRAYSCALE_GAMMA_2_2,
BABL_GRAYSCALE_ALPHA,
BABL_GRAYSCALE_ALPHA_PREMULTIPLIED,
+ BABL_YCBCR,
+ BABL_YCBCRA,
+ BABL_LAB,
+ BABL_LAB_ALPHA,
+ BABL_CMY,
+ BABL_CMYK,
+ BABL_CMYKA,
BABL_PIXEL_FORMAT_BASE = 100000,
BABL_SRGB,
h_sources = \
- babl-base.h
+ babl-base.h \
+ cpercep.h
c_sources = \
babl-base.c \
+ cpercep.c \
type-double.c \
type-float.c \
type-u8.c \
type-u16.c \
model-rgb.c \
- model-grayscale.c
+ model-grayscale.c \
+ model-lab.c \
+ model-ycbcr.c
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/babl
.cvsignore \
rgb-constants.h \
util.h
-
LDADD = -lm
void babl_base_model_rgb (void);
void babl_base_model_grayscale (void);
+void babl_base_model_ycbcr (void);
+void babl_base_model_lab (void);
static void
models (void)
babl_base_model_rgb (); /* must be registered first since it is the
reference */
babl_base_model_grayscale ();
+ babl_base_model_lab ();
+ babl_base_model_ycbcr ();
}
+
--- /dev/null
+/*
+Copyright (C) 1999-2002 Adam D. Moss (the "Author"). All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is fur-
+nished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
+NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
+NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the Author of the
+Software shall not be used in advertising or otherwise to promote the sale,
+use or other dealings in this Software without prior written authorization
+from the Author.
+*/
+
+/*
+ cpercep.c: The CPercep Functions v0.9: 2002-02-10
+ Adam D. Moss: adam@gimp.org <http://www.foxbox.org/adam/code/cpercep/>
+
+ This code module concerns itself with conversion from a hard-coded
+ RGB colour space (sRGB by default) to CIE L*a*b* and back again with
+ (primarily) precision and (secondarily) speed, oriented largely
+ towards the purposes of quantifying the PERCEPTUAL difference between
+ two arbitrary RGB colours with a minimum of fuss.
+
+ Motivation One: The author is disheartened at the amount of graphics
+ processing software around which uses weighted or non-weighted
+ Euclidean distance between co-ordinates within a (poorly-defined) RGB
+ space as the basis of what should really be an estimate of perceptual
+ difference to the human eye. Certainly it's fast to do it that way,
+ but please think carefully about whether your particular application
+ should be tolerating sloppy results for the sake of real-time response.
+
+ Motivation Two: Lack of tested, re-usable and free code available
+ for this purpose. The difficulty in finding something similar to
+ CPercep with a free license motivated this project; I hope that this
+ code also serves to illustrate how to perform the
+ R'G'B'->XYZ->L*a*b*->XYZ->R'G'B' transformation correctly since I
+ was distressed to note how many of the equations and code snippets
+ on the net were omitting the reverse transform and/or were using
+ incorrectly-derived or just plain wrong constants.
+
+ TODO: document functions, rename erroneously-named arguments
+*/
+
+/* defines added to make it compile outside gimp */
+
+#ifndef gboolean
+#define gboolean int
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+
+#include "config.h"
+#include <math.h>
+
+#ifndef __GLIBC__
+/* cbrt() is a GNU extension */
+#define cbrt(x) (pow(x, 1.0/3.0))
+#endif
+
+#include "cpercep.h"
+
+
+/* defines:
+
+ SANITY: emits warnings when passed non-sane colours (and usually
+ corrects them) -- useful when debugging.
+
+ APPROX: speeds up the conversion from RGB to the colourspace by
+ assuming that the RGB values passed in are integral and definitely
+ in the range 0->255
+
+ SRGB: assumes that the RGB values being passed in (and out) are
+ destined for an sRGB-alike display device (a typical modern monitor)
+ -- if you change this then you'll probably want to change ASSUMED_GAMMA,
+ the phosphor colours and the white point definition.
+*/
+
+/* #define SANITY */
+/* #define APPROX */
+/* #define SRGB */
+
+
+#ifdef SRGB
+#define ASSUMED_GAMMA (2.2F)
+#else
+/*#define ASSUMED_GAMMA (2.591F)*/
+#define ASSUMED_GAMMA (1.0F)
+#endif
+
+#define REV_GAMMA ((1.0F / ASSUMED_GAMMA))
+
+
+/* define characteristics of the source RGB space (and the space
+ within which we try to behave linearly). */
+
+/* Phosphor colours: */
+
+/* sRGB/HDTV phosphor colours */
+static const double pxr = 0.64F;
+static const double pyr = 0.33F;
+static const double pxg = 0.30F;
+static const double pyg = 0.60F;
+static const double pxb = 0.15F;
+static const double pyb = 0.06F;
+
+/* White point: */
+
+/* D65 (6500K) (recommended but not a common display default) */
+static const double lxn = 0.312713F;
+static const double lyn = 0.329016F;
+
+/* D50 (5000K) */
+/*static const double lxn = 0.3457F; */
+/*static const double lyn = 0.3585F; */
+
+/* D55 (5500K) */
+/*static const double lxn = 0.3324F; */
+/*static const double lyn = 0.3474F; */
+
+/* D93 (9300K) (a common monitor default, but poor colour reproduction) */
+/* static const double lxn = 0.2848F; */
+/* static const double lyn = 0.2932F; */
+
+/* illum E (normalized) */
+/*static const double lxn = 1.0/3.0F; */
+/*static const double lyn = 1.0/3.0F; */
+
+/* illum C (average sunlight) */
+/*static const double lxn = 0.3101F; */
+/*static const double lyn = 0.3162F; */
+
+/* illum B (direct sunlight) */
+/*static const double lxn = 0.3484F; */
+/*static const double lyn = 0.3516F; */
+
+/* illum A (tungsten lamp) */
+/*static const double lxn = 0.4476F; */
+/*static const double lyn = 0.4074F; */
+
+
+static const double LRAMP = 7.99959199F;
+
+
+static double xnn, znn;
+
+static double powtable[256];
+
+
+#ifndef CLAMP
+#define CLAMP(x,l,u) ((x)<(l)?(l):((x)>(u)?(u):(x)))
+#endif
+
+
+static void
+init_powtable(const double gamma)
+{
+ int i;
+
+#ifndef SRGB
+ /* pure gamma function */
+ for (i=0; i<256; i++)
+ {
+ powtable[i] = pow((i)/255.0F, gamma);
+ }
+#else
+ /* sRGB gamma curve */
+ for (i=0; i<11 /* 0.03928 * 255 */; i++)
+ {
+ powtable[i] = (i) / (255.0F * 12.92F);
+ }
+ for (; i<256; i++)
+ {
+ powtable[i] = pow( (((i) / 255.0F) + 0.055F) / 1.055F, 2.4F);
+ }
+#endif
+}
+
+
+typedef double CMatrix[3][3];
+typedef double CVector[3];
+
+static CMatrix Mrgb_to_xyz, Mxyz_to_rgb;
+
+static int
+Minvert (CMatrix src, CMatrix dest)
+{
+ double det;
+
+ dest[0][0] = src[1][1] * src[2][2] - src[1][2] * src[2][1];
+ dest[0][1] = src[0][2] * src[2][1] - src[0][1] * src[2][2];
+ dest[0][2] = src[0][1] * src[1][2] - src[0][2] * src[1][1];
+ dest[1][0] = src[1][2] * src[2][0] - src[1][0] * src[2][2];
+ dest[1][1] = src[0][0] * src[2][2] - src[0][2] * src[2][0];
+ dest[1][2] = src[0][2] * src[1][0] - src[0][0] * src[1][2];
+ dest[2][0] = src[1][0] * src[2][1] - src[1][1] * src[2][0];
+ dest[2][1] = src[0][1] * src[2][0] - src[0][0] * src[2][1];
+ dest[2][2] = src[0][0] * src[1][1] - src[0][1] * src[1][0];
+
+ det =
+ src[0][0] * dest[0][0] +
+ src[0][1] * dest[1][0] +
+ src[0][2] * dest[2][0];
+
+ if (det <= 0.0F)
+ {
+#ifdef SANITY
+ g_printerr ("\n\007 XXXX det: %f\n", det);
+#endif
+ return 0;
+ }
+
+ dest[0][0] /= det;
+ dest[0][1] /= det;
+ dest[0][2] /= det;
+ dest[1][0] /= det;
+ dest[1][1] /= det;
+ dest[1][2] /= det;
+ dest[2][0] /= det;
+ dest[2][1] /= det;
+ dest[2][2] /= det;
+
+ return 1;
+}
+
+
+static void
+rgbxyzrgb_init(void)
+{
+ init_powtable (ASSUMED_GAMMA);
+
+ xnn = lxn / lyn;
+ /* ynn taken as 1.0 */
+ znn = (1.0F - (lxn + lyn)) / lyn;
+
+ {
+ CMatrix MRC, MRCi;
+ double C1,C2,C3;
+
+ MRC[0][0] = pxr;
+ MRC[0][1] = pxg;
+ MRC[0][2] = pxb;
+ MRC[1][0] = pyr;
+ MRC[1][1] = pyg;
+ MRC[1][2] = pyb;
+ MRC[2][0] = 1.0F - (pxr + pyr);
+ MRC[2][1] = 1.0F - (pxg + pyg);
+ MRC[2][2] = 1.0F - (pxb + pyb);
+
+ Minvert (MRC, MRCi);
+
+ C1 = MRCi[0][0]*xnn + MRCi[0][1] + MRCi[0][2]*znn;
+ C2 = MRCi[1][0]*xnn + MRCi[1][1] + MRCi[1][2]*znn;
+ C3 = MRCi[2][0]*xnn + MRCi[2][1] + MRCi[2][2]*znn;
+
+ Mrgb_to_xyz[0][0] = MRC[0][0] * C1;
+ Mrgb_to_xyz[0][1] = MRC[0][1] * C2;
+ Mrgb_to_xyz[0][2] = MRC[0][2] * C3;
+ Mrgb_to_xyz[1][0] = MRC[1][0] * C1;
+ Mrgb_to_xyz[1][1] = MRC[1][1] * C2;
+ Mrgb_to_xyz[1][2] = MRC[1][2] * C3;
+ Mrgb_to_xyz[2][0] = MRC[2][0] * C1;
+ Mrgb_to_xyz[2][1] = MRC[2][1] * C2;
+ Mrgb_to_xyz[2][2] = MRC[2][2] * C3;
+
+ Minvert (Mrgb_to_xyz, Mxyz_to_rgb);
+ }
+}
+
+
+static void
+xyz_to_rgb (double *inx_outr,
+ double *iny_outg,
+ double *inz_outb)
+{
+ const double x = *inx_outr;
+ const double y = *iny_outg;
+ const double z = *inz_outb;
+
+ *inx_outr = Mxyz_to_rgb[0][0]*x + Mxyz_to_rgb[0][1]*y + Mxyz_to_rgb[0][2]*z;
+ *iny_outg = Mxyz_to_rgb[1][0]*x + Mxyz_to_rgb[1][1]*y + Mxyz_to_rgb[1][2]*z;
+ *inz_outb = Mxyz_to_rgb[2][0]*x + Mxyz_to_rgb[2][1]*y + Mxyz_to_rgb[2][2]*z;
+}
+
+
+static void
+rgb_to_xyz (double *inr_outx,
+ double *ing_outy,
+ double *inb_outz)
+{
+ const double r = *inr_outx;
+ const double g = *ing_outy;
+ const double b = *inb_outz;
+
+ *inr_outx = Mrgb_to_xyz[0][0]*r + Mrgb_to_xyz[0][1]*g + Mrgb_to_xyz[0][2]*b;
+ *ing_outy = Mrgb_to_xyz[1][0]*r + Mrgb_to_xyz[1][1]*g + Mrgb_to_xyz[1][2]*b;
+ *inb_outz = Mrgb_to_xyz[2][0]*r + Mrgb_to_xyz[2][1]*g + Mrgb_to_xyz[2][2]*b;
+}
+
+
+static inline double
+ffunc(const double t)
+{
+ if (t > 0.008856F)
+ {
+ return (cbrt(t));
+ }
+ else
+ {
+ return (7.787F * t + 16.0F/116.0F);
+ }
+}
+
+
+static inline double
+ffunc_inv(const double t)
+{
+ if (t > 0.206893F)
+ {
+ return (t * t * t);
+ }
+ else
+ {
+ return ((t - 16.0F/116.0F) / 7.787F);
+ }
+}
+
+
+static void
+xyz_to_lab (double *inx,
+ double *iny,
+ double *inz)
+{
+ double L,a,b;
+ double ffuncY;
+ const double X = *inx;
+ const double Y = *iny;
+ const double Z = *inz;
+
+ if (Y > 0.0F)
+ {
+ if (Y > 0.008856F)
+ {
+ L = (116.0F * cbrt(Y)) - 16.0F;
+ }
+ else
+ {
+ L = (Y * 903.3F);
+ }
+
+#ifdef SANITY
+ if (L < 0.0F)
+ {
+ g_printerr (" <eek1>%f \007",(float)L);
+ }
+
+ if (L > 100.0F)
+ {
+ g_printerr (" <eek2>%f \007",(float)L);
+ }
+#endif
+ }
+ else
+ {
+ L = 0.0;
+ }
+
+ ffuncY = ffunc(Y);
+ a = 500.0F * (ffunc(X/xnn) - ffuncY);
+ b = 200.0F * (ffuncY - ffunc(Z/znn));
+
+ *inx = L;
+ *iny = a;
+ *inz = b;
+}
+
+
+static void
+lab_to_xyz (double *inl,
+ double *ina,
+ double *inb)
+{
+ double X,Y,Z;
+ double P;
+ const double L = *inl;
+ const double a = *ina;
+ const double b = *inb;
+
+ if (L > LRAMP)
+ {
+ P = Y = (L + 16.0F) / 116.0F;
+ Y = Y * Y * Y;
+ }
+ else
+ {
+ Y = L / 903.3F;
+ P = 7.787F * Y + 16.0F/116.0F;
+ }
+
+ X = (P + a / 500.0F);
+ X = xnn * ffunc_inv(X);
+ Z = (P - b / 200.0F);
+ Z = znn * ffunc_inv(Z);
+
+#ifdef SANITY
+ if (X<-0.00000F)
+ {
+ if (X<-0.0001F)
+ g_printerr ("{badX %f {%f,%f,%f}}",X,L,a,b);
+ X = 0.0F;
+ }
+ if (Y<-0.00000F)
+ {
+ if (Y<-0.0001F)
+ g_printerr ("{badY %f}",Y);
+ Y = 0.0F;
+ }
+ if (Z<-0.00000F)
+ {
+ if (Z<-0.1F)
+ g_printerr ("{badZ %f}",Z);
+ Z = 0.0F;
+ }
+#endif
+
+ *inl = X;
+ *ina = Y;
+ *inb = Z;
+}
+
+
+
+/* call this before using the CPercep function */
+void
+cpercep_init (void)
+{
+ static gboolean initialized = FALSE;
+
+ if (! initialized)
+ {
+ rgbxyzrgb_init();
+ initialized = TRUE;
+ }
+}
+
+void
+cpercep_rgb_to_space (double inr,
+ double ing,
+ double inb,
+ double *outr,
+ double *outg,
+ double *outb)
+{
+#ifdef APPROX
+#ifdef SANITY
+ /* ADM extra sanity */
+ if ((inr) > 255.0F ||
+ (ing) > 255.0F ||
+ (inb) > 255.0F ||
+ (inr) < -0.0F ||
+ (ing) < -0.0F ||
+ (inb) < -0.0F
+ )
+ abort();
+#endif /* SANITY */
+ inr = powtable[(int)inr];
+ ing = powtable[(int)ing];
+ inb = powtable[(int)inb];
+#else
+#ifdef SRGB
+ /* sRGB gamma curve */
+ if (inr <= (0.03928F * 255.0F))
+ inr = inr / (255.0F * 12.92F);
+ else
+ inr = pow( (inr + (0.055F * 255.0F)) / (1.055F * 255.0F), 2.4F);
+
+ if (ing <= (0.03928F * 255.0F))
+ ing = ing / (255.0F * 12.92F);
+ else
+ ing = pow( (ing + (0.055F * 255.0F)) / (1.055F * 255.0F), 2.4F);
+
+ if (inb <= (0.03928F * 255.0F))
+ inb = inb / (255.0F * 12.92F);
+ else
+ inb = pow( (inb + (0.055F * 255.0F)) / (1.055F * 255.0F), 2.4F);
+#else
+ /* pure gamma function */
+
+ /* babl uses normalized RGB
+ inr = pow((inr)/255.0F, ASSUMED_GAMMA);
+ ing = pow((ing)/255.0F, ASSUMED_GAMMA);
+ inb = pow((inb)/255.0F, ASSUMED_GAMMA);
+ */
+#endif /* SRGB */
+#endif /* APPROX */
+
+#ifdef SANITY
+ /* ADM extra sanity */
+ if ((inr) > 1.0F ||
+ (ing) > 1.0F ||
+ (inb) > 1.0F ||
+ (inr) < 0.0F ||
+ (ing) < 0.0F ||
+ (inb) < 0.0F
+ )
+ {
+ g_printerr ("%%");
+ /* abort(); */
+ }
+#endif /* SANITY */
+
+ rgb_to_xyz(&inr, &ing, &inb);
+
+#ifdef SANITY
+ if (inr < 0.0F || ing < 0.0F || inb < 0.0F)
+ {
+ g_printerr (" [BAD2 XYZ: %f,%f,%f]\007 ",
+ inr,ing,inb);
+ }
+#endif /* SANITY */
+
+ xyz_to_lab(&inr, &ing, &inb);
+
+ *outr = inr;
+ *outg = ing;
+ *outb = inb;
+}
+
+
+void
+cpercep_space_to_rgb (double inr,
+ double ing,
+ double inb,
+ double *outr,
+ double *outg,
+ double *outb)
+{
+ lab_to_xyz(&inr, &ing, &inb);
+
+#ifdef SANITY
+ if (inr<-0.0F || ing<-0.0F || inb<-0.0F)
+ {
+ g_printerr (" [BAD1 XYZ: %f,%f,%f]\007 ",
+ inr,ing,inb);
+ }
+#endif
+
+ xyz_to_rgb(&inr, &ing, &inb);
+
+ /* yes, essential. :( */
+ inr = CLAMP(inr,0.0F,1.0F);
+ ing = CLAMP(ing,0.0F,1.0F);
+ inb = CLAMP(inb,0.0F,1.0F);
+
+#ifdef SRGB
+ if (inr <= 0.0030402477F)
+ inr = inr * (12.92F * 255.0F);
+ else
+ inr = pow(inr, 1.0F/2.4F) * (1.055F * 255.0F) - (0.055F * 255.0F);
+
+ if (ing <= 0.0030402477F)
+ ing = ing * (12.92F * 255.0F);
+ else
+ ing = pow(ing, 1.0F/2.4F) * (1.055F * 255.0F) - (0.055F * 255.0F);
+
+ if (inb <= 0.0030402477F)
+ inb = inb * (12.92F * 255.0F);
+ else
+ inb = pow(inb, 1.0F/2.4F) * (1.055F * 255.0F) - (0.055F * 255.0F);
+#else
+ /* babl uses normalized RGB values
+ inr = 255.0F * pow(inr, REV_GAMMA);
+ ing = 255.0F * pow(ing, REV_GAMMA);
+ inb = 255.0F * pow(inb, REV_GAMMA);
+ */
+#endif
+
+ *outr = inr;
+ *outg = ing;
+ *outb = inb;
+}
+
+
+#if 0
+/* EXPERIMENTAL SECTION */
+
+const double
+xscaler(const double start, const double end,
+ const double me, const double him)
+{
+ return start + ((end-start) * him) / (me + him);
+}
+
+
+void
+mix_colours (const double L1, const double a1, const double b1,
+ const double L2, const double a2, const double b2,
+ double *rtnL, double *rtna, double *rtnb,
+ double mass1, double mass2)
+{
+ double w1, w2;
+
+#if 0
+ *rtnL = xscaler (L1, L2, mass1, mass2);
+ *rtna = xscaler (a1, a2, mass1, mass2);
+ *rtnb = xscaler (b1, b2, mass1, mass2);
+#else
+
+#if 1
+ w1 = mass1 * L1;
+ w2 = mass2 * L2;
+#else
+ w1 = mass1 * (L1*L1*L1);
+ w2 = mass2 * (L2*L2*L2);
+#endif
+
+ *rtnL = xscaler (L1, L2, mass1, mass2);
+
+ if (w1 <= 0.0 &&
+ w2 <= 0.0)
+ {
+ *rtna =
+ *rtnb = 0.0;
+#ifdef SANITY
+ /* g_printerr ("\007OUCH. "); */
+#endif
+ }
+ else
+ {
+ *rtna = xscaler(a1, a2, w1, w2);
+ *rtnb = xscaler(b1, b2, w1, w2);
+ }
+#endif
+}
+#endif /* EXPERIMENTAL SECTION */
--- /dev/null
+/*
+Copyright (C) 1997-2002 Adam D. Moss (the "Author"). All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is fur-
+nished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
+NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
+NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the Author of the
+Software shall not be used in advertising or otherwise to promote the sale,
+use or other dealings in this Software without prior written authorization
+from the Author.
+*/
+
+/*
+ cpercep.c: The CPercep Functions v0.9: 2002-02-10
+ Adam D. Moss: adam@gimp.org <http://www.foxbox.org/adam/code/cpercep/>
+
+ TODO: document functions, rename erroneously-named arguments
+*/
+
+#ifndef __CPERCEP_H__
+#define __CPERCEP_H__
+
+
+void cpercep_init (void);
+
+void cpercep_rgb_to_space (double inr,
+ double ing,
+ double inb,
+ double *outr,
+ double *outg,
+ double *outb);
+
+void cpercep_space_to_rgb (double inr,
+ double ing,
+ double inb,
+ double *outr,
+ double *outg,
+ double *outb);
+
+
+#if 0
+/* This is in the header so that it can potentially be inlined. */
+static const double
+cpercep_distance_space (const double L1, const double a1, const double b1,
+ const double L2, const double a2, const double b2)
+{
+ const double Ld = L1 - L2;
+ const double ad = a1 - a2;
+ const double bd = b1 - b2;
+
+ return (Ld*Ld + ad*ad + bd*bd);
+}
+#endif
+
+
+#endif /* __CPERCEP_H__ */
);
}
+static void
+rgb_to_cmyk (int src_bands,
+ void **src,
+ int *src_pitch,
+ int dst_bands,
+ void **dst,
+ int *dst_pitch,
+ int n)
+{
+ BABL_PLANAR_SANITY
+
+ while (n--)
+ {
+ double red = *(double*)src[0];
+ double green = *(double*)src[1];
+ double blue = *(double*)src[2];
+
+ double cyan, magenta, yellow, key;
+
+ double pullout = 1.0;
+
+ cyan = 1.0 - red;
+ magenta = 1.0 - green;
+ yellow = 1.0 - blue;
+
+ key = 1.0;
+ if (cyan < key) key = cyan;
+ if (magenta < key) key = magenta;
+ if (yellow < key) key = yellow;
+
+ key *= pullout;
+
+ if (key < 1.0)
+ {
+ cyan = (cyan - key) / (1.0 -key);
+ magenta = (magenta - key) / (1.0 -key);
+ yellow = (yellow - key) / (1.0 -key);
+ }
+ else
+ {
+ cyan = 0.0;
+ magenta = 0.0;
+ yellow = 0.0;
+ }
+
+ *(double*)dst[0] = cyan;
+ *(double*)dst[1] = magenta;
+ *(double*)dst[2] = yellow;
+ *(double*)dst[3] = key;
+
+ if (dst_bands > 4) /* alpha passthorugh */
+ *(double*)dst[4] = (src_bands>3)?*(double*)src[3]:1.0;
+
+ BABL_PLANAR_STEP
+ }
+}
+
+static void
+cmyk_to_rgb (int src_bands,
+ void **src,
+ int *src_pitch,
+ int dst_bands,
+ void **dst,
+ int *dst_pitch,
+ int n)
+{
+ BABL_PLANAR_SANITY
+
+ while (n--)
+ {
+ double cyan = *(double*)src[0];
+ double yellow = *(double*)src[1];
+ double magenta = *(double*)src[2];
+ double key = *(double*)src[3];
+
+ double red, green, blue;
+
+ if (key < 1.0)
+ {
+ cyan = cyan * (1.0 - key) + key;
+ magenta = magenta * (1.0 - key) + key;
+ yellow = yellow * (1.0 - key) + key;
+ }
+ else
+ {
+ cyan = magenta = yellow = 1.0;
+ }
+
+ red = 1.0 - cyan;
+ green = 1.0 - magenta;
+ blue = 1.0 - yellow;
+
+ *(double*)dst[0] = red;
+ *(double*)dst[1] = green;
+ *(double*)dst[2] = blue;
+
+ if (dst_bands > 3) /* alpha passthorugh */
+ *(double*)dst[3] = (src_bands>4)?*(double*)src[4]:1.0;
+
+ BABL_PLANAR_STEP
+ }
+}
+
+#if 0
static void
rgb_to_and_from_cmy (int src_bands,
void **src,
BABL_PLANAR_STEP
}
}
+#endif
static void
conversions (void)
babl_conversion_new (
"babl-base: rgba to cmy",
"source", babl_model_id (BABL_RGBA),
- "destination", babl_model_id (BABL_CMY),
- "planar", rgb_to_and_from_cmy,
+ "destination", babl_model_id (BABL_CMYK),
+ "planar", rgb_to_cmyk,
NULL
);
babl_conversion_new (
"babl-base: cmy to rgba",
- "source", babl_model_id (BABL_CMY),
+ "source", babl_model_id (BABL_CMYK),
"destination", babl_model_id (BABL_RGBA),
- "planar", rgb_to_and_from_cmy,
+ "planar", cmyk_to_rgb,
NULL
);
}
static void
pixel_formats (void)
{
- babl_pixel_format_new (
- "cmyk-float",
- "id", BABL_CMYK_FLOAT,
- babl_model_id (BABL_CMYK),
- babl_type_id (BABL_FLOAT),
- babl_component_id (BABL_CYAN),
- babl_component_id (BABL_MAGENTA),
- babl_component_id (BABL_YELLOW),
- babl_component_id (BABL_KEY),
- NULL);
-
- babl_pixel_format_new (
- "cmyka-float",
- "id", BABL_CMYKA_FLOAT,
- babl_model_id (BABL_CMYKA),
- babl_type_id (BABL_FLOAT),
- babl_component_id (BABL_CYAN),
- babl_component_id (BABL_MAGENTA),
- babl_component_id (BABL_YELLOW),
- babl_component_id (BABL_KEY),
- babl_component_id (BABL_ALPHA),
- NULL);
}
--- /dev/null
+/* babl - dynamically extendable universal pixel conversion library.
+ * Copyright (C) 2005, Øyvind Kolås.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include "babl.h"
+#include "util.h"
+#include "cpercep.h"
+
+static void components (void);
+static void models (void);
+static void conversions (void);
+static void pixel_formats (void);
+
+void
+babl_base_model_lab (void)
+{
+ cpercep_init ();
+ components ();
+ models ();
+ conversions ();
+ pixel_formats ();
+}
+
+static void
+components (void)
+{
+ babl_component_new (
+ "L",
+ "id", BABL_LAB_L,
+ "luma",
+ NULL);
+
+ babl_component_new (
+ "a",
+ "id", BABL_LAB_A,
+ "chroma",
+ NULL);
+
+ babl_component_new (
+ "b",
+ "id", BABL_LAB_B,
+ "chroma",
+ NULL);
+}
+
+static void
+models (void)
+{
+ babl_model_new (
+ "CIE Lab",
+ "id", BABL_LAB,
+ babl_component_id (BABL_LAB_L),
+ babl_component_id (BABL_LAB_A),
+ babl_component_id (BABL_LAB_B),
+ NULL);
+
+ babl_model_new (
+ "CIE Lab alpha",
+ "id", BABL_LAB_ALPHA,
+ babl_component_id (BABL_LAB_L),
+ babl_component_id (BABL_LAB_A),
+ babl_component_id (BABL_LAB_B),
+ babl_component_id (BABL_ALPHA),
+ NULL);
+}
+
+static void
+rgb_to_lab (int src_bands,
+ void **src,
+ int *src_pitch,
+ int dst_bands,
+ void **dst,
+ int *dst_pitch,
+ int n)
+{
+ BABL_PLANAR_SANITY
+
+ while (n--)
+ {
+ double red = *(double*)src[0];
+ double green = *(double*)src[1];
+ double blue = *(double*)src[2];
+
+ double L, a, b;
+
+ cpercep_rgb_to_space (red, green, blue, &L, &a, &b);
+
+ *(double*)dst[0] = L;
+ *(double*)dst[1] = a;
+ *(double*)dst[2] = b;
+
+ if (dst_bands > 3) /* alpha passthorugh */
+ *(double*)dst[3] = (src_bands>3)?*(double*)src[3]:1.0;
+
+ BABL_PLANAR_STEP
+ }
+}
+
+static void
+lab_to_rgb (int src_bands,
+ void **src,
+ int *src_pitch,
+ int dst_bands,
+ void **dst,
+ int *dst_pitch,
+ int n)
+{
+ BABL_PLANAR_SANITY
+
+ while (n--)
+ {
+ double L = *(double*)src[0];
+ double a = *(double*)src[1];
+ double b = *(double*)src[2];
+
+ double red, green, blue;
+
+ cpercep_space_to_rgb (L, a, b, &red, &green, &blue);
+
+ *(double*)dst[0] = red;
+ *(double*)dst[1] = green;
+ *(double*)dst[2] = blue;
+
+ if (dst_bands > 3) /* alpha passthorugh */
+ *(double*)dst[3] = (src_bands>3)?*(double*)src[3]:1.0;
+
+ BABL_PLANAR_STEP
+ }
+}
+
+static void
+conversions (void)
+{
+ babl_conversion_new (
+ "babl-base: rgba to lab",
+ "source", babl_model_id (BABL_RGBA),
+ "destination", babl_model_id (BABL_LAB),
+ "planar", rgb_to_lab,
+ NULL
+ );
+ babl_conversion_new (
+ "babl-base: lab to rgba",
+ "source", babl_model_id (BABL_LAB),
+ "destination", babl_model_id (BABL_RGBA),
+ "planar", lab_to_rgb,
+ NULL
+ );
+ babl_conversion_new (
+ "babl-base: rgb to lab",
+ "source", babl_model_id (BABL_RGB),
+ "destination", babl_model_id (BABL_LAB),
+ "planar", rgb_to_lab,
+ NULL
+ );
+ babl_conversion_new (
+ "babl-base: lab to rgb",
+ "source", babl_model_id (BABL_LAB),
+ "destination", babl_model_id (BABL_RGB),
+ "planar", lab_to_rgb,
+ NULL
+ );
+ babl_conversion_new (
+ "babl-base: rgba to laba",
+ "source", babl_model_id (BABL_RGBA),
+ "destination", babl_model_id (BABL_LAB_ALPHA),
+ "planar", rgb_to_lab,
+ NULL
+ );
+ babl_conversion_new (
+ "babl-base: laba to rgba",
+ "source", babl_model_id (BABL_LAB_ALPHA),
+ "destination", babl_model_id (BABL_RGBA),
+ "planar", lab_to_rgb,
+ NULL
+ );
+}
+
+static void
+pixel_formats (void)
+{
+}
"rgba-double",
"id", BABL_RGBA_DOUBLE,
babl_model_id (BABL_RGBA),
- babl_type_id (BABL_FLOAT),
+ babl_type_id (BABL_DOUBLE),
babl_component_id (BABL_RED),
babl_component_id (BABL_GREEN),
babl_component_id (BABL_BLUE),
static void
components (void)
{
- babl_component_new (
- "Cb",
+ babl_component_new (
+ "cb",
"id", BABL_CB,
"chroma",
NULL);
babl_component_new (
- "Cr",
+ "cr",
"id", BABL_CR,
"chroma",
NULL);
static void
models (void)
{
+ babl_model_new (
+ "ycbcr",
+ "id", BABL_YCBCR,
+ babl_component_id (BABL_LUMINANCE),
+ babl_component_id (BABL_CB),
+ babl_component_id (BABL_CR),
+ NULL);
+
+ babl_model_new (
+ "ycbcra",
+ "id", BABL_YCBCRA,
+ babl_component_id (BABL_LUMINANCE),
+ babl_component_id (BABL_CB),
+ babl_component_id (BABL_CR),
+ babl_component_id (BABL_ALPHA),
+ NULL);
+}
+
+static void
+rgb_to_ycbcr (int src_bands,
+ void **src,
+ int *src_pitch,
+ int dst_bands,
+ void **dst,
+ int *dst_pitch,
+ int n)
+{
+ BABL_PLANAR_SANITY
+
+ while (n--)
+ {
+ double red = *(double*)src[0];
+ double green = *(double*)src[1];
+ double blue = *(double*)src[2];
+
+ double luminance, cb, cr;
+
+ luminance = 0.299 * red +
+ 0.587 * green +
+ 0.114 * blue;
+ cb = (-0.1687) * red
+ -0.3313 * green +
+ 0.5 * blue;
+ cr = 0.5 * red
+ -0.4187 * green +
+ -0.0813 * blue;
+
+ *(double*)dst[0] = luminance;
+ *(double*)dst[1] = cb;
+ *(double*)dst[2] = cr;
+
+ if (dst_bands > 3) /* alpha passthorugh */
+ *(double*)dst[3] = (src_bands>3)?*(double*)src[3]:1.0;
+
+ BABL_PLANAR_STEP
+ }
+}
+
+static void
+ycbcr_to_rgb (int src_bands,
+ void **src,
+ int *src_pitch,
+ int dst_bands,
+ void **dst,
+ int *dst_pitch,
+ int n)
+{
+ BABL_PLANAR_SANITY
+
+ while (n--)
+ {
+ double luminance = *(double*)src[0];
+ double cb = *(double*)src[1];
+ double cr = *(double*)src[2];
+
+ double red, green, blue;
+
+ red = luminance + 1.40200 * cr;
+ green = luminance - 0.34414 * cb - 0.71414 *cr;
+ blue = luminance + 1.77200 * cb;
+
+
+ *(double*)dst[0] = red;
+ *(double*)dst[1] = green;
+ *(double*)dst[2] = blue;
+
+ if (dst_bands > 3) /* alpha passthorugh */
+ *(double*)dst[3] = (src_bands>3)?*(double*)src[3]:1.0;
+
+ BABL_PLANAR_STEP
+ }
}
static void
conversions (void)
{
+ babl_conversion_new (
+ "babl-base: rgba to ycbcr",
+ "source", babl_model_id (BABL_RGBA),
+ "destination", babl_model_id (BABL_YCBCR),
+ "planar", rgb_to_ycbcr,
+ NULL
+ );
+ babl_conversion_new (
+ "babl-base: ycbcr to rgba",
+ "source", babl_model_id (BABL_YCBCR),
+ "destination", babl_model_id (BABL_RGBA),
+ "planar", ycbcr_to_rgb,
+ NULL
+ );
+ babl_conversion_new (
+ "babl-base: rgb to ycbcr",
+ "source", babl_model_id (BABL_RGB),
+ "destination", babl_model_id (BABL_YCBCR),
+ "planar", rgb_to_ycbcr,
+ NULL
+ );
+ babl_conversion_new (
+ "babl-base: ycbcr to rgb",
+ "source", babl_model_id (BABL_YCBCR),
+ "destination", babl_model_id (BABL_RGB),
+ "planar", ycbcr_to_rgb,
+ NULL
+ );
+ babl_conversion_new (
+ "babl-base: rgba to ycbcra",
+ "source", babl_model_id (BABL_RGBA),
+ "destination", babl_model_id (BABL_YCBCRA),
+ "planar", rgb_to_ycbcr,
+ NULL
+ );
+ babl_conversion_new (
+ "babl-base: ycbcra to rgba",
+ "source", babl_model_id (BABL_YCBCRA),
+ "destination", babl_model_id (BABL_RGBA),
+ "planar", ycbcr_to_rgb,
+ NULL
+ );
}
static void
{
while (n--)
{
- (*(double *) dst) = (*(unsigned short *) src*65535.0);
+ (*(double *) dst) = (*(unsigned short *) src / 65535.0);
dst += 8;
src += 2;
}
TESTS = \
float_to_u8 \
grayscale_to_rgb \
- u8_to_float
-
-float_to_u8_SOURCES = float_to_u8.c
-u8_to_float_SOURCES = u8_to_float.c
-grayscale_to_rgb_SOURCES = grayscale_to_rgb.c
+ u8_to_float \
+ rgb_to_lab_to_rgb \
+ rgb_to_ycbcr \
+ rgb_to_ycbcr_to_rgb
+
+float_to_u8_SOURCES = float_to_u8.c
+u8_to_float_SOURCES = u8_to_float.c
+grayscale_to_rgb_SOURCES = grayscale_to_rgb.c
+rgb_to_lab_to_rgb_SOURCES = rgb_to_lab_to_rgb.c
+rgb_to_ycbcr_SOURCES = rgb_to_ycbcr.c
+rgb_to_ycbcr_to_rgb_SOURCES = rgb_to_ycbcr_to_rgb.c
AM_CFLAGS = -I$(top_srcdir) -I$(top_srcdir)/babl
--- /dev/null
+/* babl - dynamically extendable universal pixel conversion library.
+ * Copyright (C) 2005, Øyvind Kolås.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#include <math.h>
+#include "babl.h"
+#include "babl-internal.h"
+
+#define PIXELS 6
+#define TOLERANCE 0.001
+
+float source_buf [PIXELS*3]=
+ {0.0, 0.0, 0.0,
+ 0.5, 0.5, 0.5,
+ 1.0, 1.0, 1.0,
+ 1.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0,
+ 0.0, 0.0, 1.0};
+
+float temp_buf [PIXELS*3];
+float destination_buf [PIXELS*3];
+
+int
+test (void)
+{
+ BablFish *fish;
+ int i;
+ int OK=1;
+
+
+ fish = babl_fish (
+ (Babl*) babl_pixel_format_new (
+ "foo",
+ babl_model ("rgb"),
+ babl_type ("float"),
+ babl_component ("red"),
+ babl_component ("green"),
+ babl_component ("blue"),
+ NULL
+ ),
+ (Babl*) babl_pixel_format_new (
+ "bar",
+ babl_model ("CIE Lab"),
+ babl_type ("float"),
+ babl_component ("L"),
+ babl_component ("a"),
+ babl_component ("b"),
+ NULL
+ )
+ );
+
+ babl_fish_process (fish, source_buf, temp_buf, PIXELS);
+
+ fish = babl_fish ((Babl*) babl_pixel_format ("bar"),
+ (Babl*) babl_pixel_format ("foo"));
+
+ babl_fish_process (fish, temp_buf, destination_buf, PIXELS);
+
+ for (i=0; i<PIXELS * 3; i++)
+ {
+ if (fabs(destination_buf[i] - source_buf[i]) > TOLERANCE)
+ {
+ babl_log ("%2i (%2i%%3=%i, %2i/3=%i) is %f should be %f",
+ i, i,i%3, i,i/3, destination_buf[i], source_buf[i]);
+ OK=0;
+ }
+ }
+
+ if (!OK)
+ return -1;
+ return 0;
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ babl_init ();
+ if (test())
+ return -1;
+ babl_destroy ();
+ return 0;
+}
--- /dev/null
+/* babl - dynamically extendable universal pixel conversion library.
+ * Copyright (C) 2005, Øyvind Kolås.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#include <math.h>
+#include "babl.h"
+#include "babl-internal.h"
+
+#define PIXELS 6
+#define TOLERANCE 0.000001
+
+float source_buf [PIXELS*3]=
+ {0.0, 0.0, 0.0,
+ 0.5, 0.5, 0.5,
+ 1.0, 1.0, 1.0,
+ 1.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0,
+ 0.0, 0.0, 1.0};
+
+float reference_buf [PIXELS*3]=
+ {0.0, 0.0, 0.0,
+ 0.5, 0.0, 0.0,
+ 1.0, 0.0, 0.0,
+ 0.299,-0.1687, 0.5,
+ 0.587,-0.3313,-0.4187,
+ 0.114, 0.5, -0.081300};
+
+
+float destination_buf [PIXELS*3];
+
+int
+test (void)
+{
+ BablFish *fish;
+ int i;
+ int OK=1;
+
+
+ fish = babl_fish (
+ (Babl*) babl_pixel_format_new (
+ "foo",
+ babl_model ("rgb"),
+ babl_type ("float"),
+ babl_component ("red"),
+ babl_component ("green"),
+ babl_component ("blue"),
+ NULL
+ ),
+ (Babl*) babl_pixel_format_new (
+ "bar",
+ babl_model ("ycbcr"),
+ babl_type ("float"),
+ babl_component ("luminance"),
+ babl_component ("cb"),
+ babl_component ("cr"),
+ NULL
+ )
+ );
+
+ babl_fish_process (fish, source_buf, destination_buf, PIXELS);
+
+ for (i=0; i<PIXELS * 3; i++)
+ {
+ if (fabs(destination_buf[i] - reference_buf[i]) > TOLERANCE)
+ {
+ babl_log ("%2i (%2i%%3=%i, %2i/3=%i) is %f should be %f",
+ i, i,i%3, i,i/3, destination_buf[i], reference_buf[i]);
+ OK=0;
+ }
+ }
+ if (!OK)
+ return -1;
+ return 0;
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ babl_init ();
+ if (test())
+ return -1;
+ babl_destroy ();
+ return 0;
+}
--- /dev/null
+/* babl - dynamically extendable universal pixel conversion library.
+ * Copyright (C) 2005, Øyvind Kolås.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#include <math.h>
+#include "babl.h"
+#include "babl-internal.h"
+
+#define PIXELS 6
+#define TOLERANCE 0.001
+
+float source_buf [PIXELS*3]=
+ {0.0, 0.0, 0.0,
+ 0.5, 0.5, 0.5,
+ 1.0, 1.0, 1.0,
+ 1.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0,
+ 0.0, 0.0, 1.0};
+
+float temp_buf [PIXELS*3];
+float destination_buf [PIXELS*3];
+
+int
+test (void)
+{
+ BablFish *fish;
+ int i;
+ int OK=1;
+
+
+ fish = babl_fish (
+ (Babl*) babl_pixel_format_new (
+ "foo",
+ babl_model ("rgb"),
+ babl_type ("float"),
+ babl_component ("red"),
+ babl_component ("green"),
+ babl_component ("blue"),
+ NULL
+ ),
+ (Babl*) babl_pixel_format_new (
+ "bar",
+ babl_model ("ycbcr"),
+ babl_type ("float"),
+ babl_component ("luminance"),
+ babl_component ("cb"),
+ babl_component ("cr"),
+ NULL
+ )
+ );
+
+ babl_fish_process (fish, source_buf, temp_buf, PIXELS);
+
+ fish = babl_fish ((Babl*) babl_pixel_format ("bar"),
+ (Babl*) babl_pixel_format ("foo"));
+
+ babl_fish_process (fish, temp_buf, destination_buf, PIXELS);
+
+ for (i=0; i<PIXELS * 3; i++)
+ {
+ if (fabs(destination_buf[i] - source_buf[i]) > TOLERANCE)
+ {
+ babl_log ("%2i (%2i%%3=%i, %2i/3=%i) is %f should be %f",
+ i, i,i%3, i,i/3, destination_buf[i], source_buf[i]);
+ OK=0;
+ }
+ }
+ if (!OK)
+ return -1;
+ return 0;
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ babl_init ();
+ if (test())
+ return -1;
+ babl_destroy ();
+ return 0;
+}